package com.yigoushangcheng.oauth.service.impl;

import com.yigoushangcheng.oauth.service.AuthService;
import com.yigoushangcheng.oauth.util.AuthToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Map;

/**
 * @Auther: ljj
 * @Description:
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private RestTemplate restTemplate;


    /**
     * 认证服务
     *
     * @param clientId     客户端ID
     * @param clientSecret 客户端秘钥
     * @param username     业务用户名
     * @param password     业务用户密码
     * @return
     */
    @Override
    public AuthToken login(String clientId, String clientSecret, String username, String password) {
        AuthToken authToken = this.applyToken(clientId, clientSecret, username, password);
        if(authToken==null){
            throw new RuntimeException("认证失败");
        }
        return authToken;
    }


    private AuthToken applyToken(String clientId, String clientSecret, String username, String password){
        //1.在注册中心获取认证服务
        ServiceInstance serviceInstance = loadBalancerClient.choose("USER-AUTH");
        //2.在认证服务中取得认证请求地址
        //String path = serviceInstance.getUri().toString()+"/oauth/token";
        String path = "http://localhost:9100/oauth/token";
        //3.设置业务用户名和密码  Map
        MultiValueMap<String, String> bodyMap = new LinkedMultiValueMap<>();
        bodyMap.add("grant_type","password");    //授权模式
        bodyMap.add("username",username);
        bodyMap.add("password",password);

        //4.设置客户端的ID和秘钥（注意：要符合认证类型的加密方式）
        MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
        headers.add("Authorization",this.httpbasic(clientId,clientSecret));
        //指定 restTemplate当遇到400或401响应时候也不要抛出异常，也要正常返回值
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {
                //当响应的值为400或401时候也要正常响应，不要抛出异常
                if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401) {
                    super.handleError(response);
                }
            }
        });

        //5.使用restTemplate发出POST请求
        Map map = null;
        try {
            ResponseEntity<Map> responseEntity = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(bodyMap,headers), Map.class);
            map  = responseEntity.getBody();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //6.将返回的结果封装到AuthToken封装类中
        if(map==null||map.get("access_token")==null||map.get("refresh_token")==null||map.get("jti")==null){
            throw new RuntimeException("创建令牌失败");
        }
        AuthToken authToken = new AuthToken();
        authToken.setAccessToken((String) map.get("access_token"));
        authToken.setRefreshToken((String) map.get("refresh_token"));
        authToken.setJti((String) map.get("jti"));
        return authToken;
    }


    //客户端ID和秘钥的生成认证方式
    private String httpbasic(String clientId,String clientSecret){
        //注意httpBasic认证方式，需要将id和秘钥拼接到一起，中间要用 :
        String stringId = clientId+":"+clientSecret;
        //进行base64编码
        byte[] encode = Base64Utils.encode(stringId.getBytes());
        return "Basic "+new String(encode);
    }
}
